/**
 * File    : UniversalDaoJpa.java
 * Created : 2007-12-20
 * By      : lhg
 */
package com.luhuiguo.sso.dao.impl;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.util.Assert;

import com.luhuiguo.sso.dao.UniversalDao;

/**
 * @author lhg
 * @version $Id: UniversalDaoImpl.java 16 2008-10-17 13:13:27Z LuHuiguo $
 * 
 */
public class UniversalDaoImpl extends JpaDaoSupport implements UniversalDao {

	@SuppressWarnings("unchecked")
	protected Object first(List list) {
		if (list == null || list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	@Override
	public <T> T get(Class<T> entityClass, Serializable id) {
		Assert.notNull(id);
		if (logger.isInfoEnabled()) {
			String className = entityClass.getSimpleName();
			logger.info("finding " + className + " instance with id: " + id);
		}
		return getJpaTemplate().find(entityClass, id);
	}

	@Override
	public void create(Object entity) {
		Assert.notNull(entity);
		if (logger.isInfoEnabled()) {
			String className = entity.getClass().getSimpleName();
			logger.info("saving " + className + " instance");
		}
		getJpaTemplate().persist(entity);
		if (logger.isInfoEnabled()) {
			logger.info("save successful");
		}
	}

	@Override
	public <T> T update(T entity) {
		Assert.notNull(entity);
		if (logger.isInfoEnabled()) {
			String className = entity.getClass().getSimpleName();
			logger.info("updating " + className + " instance");
		}
		T result = getJpaTemplate().merge(entity);
		if (logger.isInfoEnabled()) {
			logger.info("update successful");
		}
		return result;
	}

	@Override
	public void delete(Object entity) {
		Assert.notNull(entity);
		if (logger.isInfoEnabled()) {
			String className = entity.getClass().getSimpleName();
			logger.info("deleting " + className + " instance");
		}
		getJpaTemplate().remove(entity);
		if (logger.isInfoEnabled()) {
			logger.info("delete successful");
		}
	}

	@Override
	public void delete(Class<?> entityClass, Serializable id) {
		Assert.notNull(id);
		if (logger.isInfoEnabled()) {
			String className = entityClass.getSimpleName();
			logger.info("deleting " + className + " instance");
		}
		getJpaTemplate().remove(get(entityClass, id));
		if (logger.isInfoEnabled()) {
			logger.info("delete successful");
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findByProperty(Class<T> entityClass,
			String propertyName, final Object value,
			final int... rowStartIdxAndCount) {
		Assert.hasLength(propertyName);
		String className = entityClass.getSimpleName();
		if (logger.isInfoEnabled()) {
			logger.info("finding " + className + " instance with property: "
					+ propertyName + ", value: " + value);
		}

		try {
			final String queryString = "select model from " + className
					+ " model where model." + propertyName + "= :propertyValue";
			return getJpaTemplate().executeFind(new JpaCallback() {
				public Object doInJpa(EntityManager em)
						throws PersistenceException {
					Query query = em.createQuery(queryString);
					query.setParameter("propertyValue", value);
					if (rowStartIdxAndCount != null
							&& rowStartIdxAndCount.length > 0) {
						int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
						if (rowStartIdx > 0) {
							query.setFirstResult(rowStartIdx);
						}

						if (rowStartIdxAndCount.length > 1) {
							int rowCount = Math.max(0, rowStartIdxAndCount[1]);
							if (rowCount > 0) {
								query.setMaxResults(rowCount);
							}
						}
					}
					return query.getResultList();
				}
			});
		} catch (RuntimeException re) {
			if (logger.isErrorEnabled()) {
				logger.error("find by property name failed", re);
			}
			throw re;
		}

	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findAll(Class<T> entityClass,
			final int... rowStartIdxAndCount) {
		String className = entityClass.getSimpleName();
		if (logger.isInfoEnabled()) {
			logger.info("finding all " + className + " instances");
		}
		try {
			final String queryString = "select model from " + className
					+ " model";
			return getJpaTemplate().executeFind(new JpaCallback() {
				public Object doInJpa(EntityManager em)
						throws PersistenceException {
					Query query = em.createQuery(queryString);
					if (rowStartIdxAndCount != null
							&& rowStartIdxAndCount.length > 0) {
						int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
						if (rowStartIdx > 0) {
							query.setFirstResult(rowStartIdx);
						}

						if (rowStartIdxAndCount.length > 1) {
							int rowCount = Math.max(0, rowStartIdxAndCount[1]);
							if (rowCount > 0) {
								query.setMaxResults(rowCount);
							}
						}
					}
					return query.getResultList();
				}
			});
		} catch (RuntimeException re) {
			if (logger.isErrorEnabled()) {
				logger.error("find all failed", re);
			}
			throw re;
		}
	}

	@Override
	public Object findFirstByNamedQuery(final String queryName,
			final Object... values) {
		Assert.hasLength(queryName);
		return first(getJpaTemplate().findByNamedQuery(queryName, values));
	}

}
